package com.example.roleplay.controller;


import com.example.roleplay.domain.KnowledgeSnippet;
import com.example.roleplay.domain.Persona;
import com.example.roleplay.domain.SessionMemory;
import com.example.roleplay.domain.Skill;
import com.example.roleplay.dto.WebSocketMessage;
import com.example.roleplay.service.PersonaService;
import com.example.roleplay.service.SessionService;
import com.example.roleplay.service.KnowledgeService;
import com.example.roleplay.service.AIEnhancementService;
import com.example.roleplay.service.asr.ASRClient;
import com.example.roleplay.service.llm.LLMClient;
import com.example.roleplay.service.tts.TTSClient;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;

import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;

/**
 * WebSocket聊天控制器
 */
@Slf4j
@Controller
@RequiredArgsConstructor
public class ChatWebSocketController {

    private final SimpMessagingTemplate messagingTemplate;
    private final SessionService sessionService;
    private final PersonaService personaService;
    private final LLMClient llmClient;
    private final ASRClient asrClient;
    private final TTSClient ttsClient;
    private final KnowledgeService knowledgeService;
    private final AIEnhancementService aiEnhancementService;
    private final ObjectMapper objectMapper;

    /**
     * 处理用户文本消息
     */
    @MessageMapping("/chat/{sessionId}/text")
    public void handleTextMessage(@DestinationVariable("sessionId") String sessionId, WebSocketMessage message) {
        try {


            if (!sessionService.isSessionValid(sessionId)) {
                sendErrorMessage(sessionId, "会话无效或已过期");
                return;
            }

            sessionService.updateSessionActivity(sessionId);
            String userText = message.getText();

            // 处理文本消息并获取LLM响应
            processTextMessage(sessionId, userText);

        } catch (Exception e) {
            log.error("处理文本消息失败", e);
            sendErrorMessage(sessionId, "处理消息失败: " + e.getMessage());
        }
    }

    /**
     * 处理用户音频消息
     */
    @MessageMapping("/chat/{sessionId}/audio")
    public void handleAudioMessage(@DestinationVariable("sessionId") String sessionId, WebSocketMessage message) {
        try {


            if (!sessionService.isSessionValid(sessionId)) {
                sendErrorMessage(sessionId, "会话无效或已过期");
                return;
            }

            sessionService.updateSessionActivity(sessionId);

            // 解码音频数据
            byte[] audioData = Base64.getDecoder().decode(message.getData());
            String format = message.getFormat() != null ? message.getFormat() : "wav";

            // ASR识别
            String transcriptionText = asrClient.transcribe(audioData, format, "zh-CN");
            log.info("ASR识别结果: {}", transcriptionText);

            // 发送识别结果给客户端
            WebSocketMessage asrResult = WebSocketMessage.builder()
                    .type(WebSocketMessage.MessageType.STATUS)
                    .content("ASR识别: " + transcriptionText)
                    .timestamp(System.currentTimeMillis())
                    .build();
            messagingTemplate.convertAndSend("/topic/chat/" + sessionId, asrResult);

            // 处理识别出的文本
            processTextMessage(sessionId, transcriptionText);

        } catch (Exception e) {
            log.error("处理音频消息失败", e);
            sendErrorMessage(sessionId, "处理音频失败: " + e.getMessage());
        }
    }

    /**
     * 心跳检测
     */
    @MessageMapping("/chat/{sessionId}/ping")
    @SendTo("/topic/chat/{sessionId}")
    public WebSocketMessage handlePing(@DestinationVariable("sessionId") String sessionId) {
        log.debug("收到心跳 - 会话: {}", sessionId);
        sessionService.updateSessionActivity(sessionId);
        return WebSocketMessage.builder()
                .type(WebSocketMessage.MessageType.PONG)
                .timestamp(System.currentTimeMillis())
                .build();
    }

    /**
     * 处理文本消息的核心逻辑
     */
    private void processTextMessage(String sessionId, String userText) {
        try {
            SessionMemory sessionMemory = sessionService.getSessionMemory(sessionId);
            if (sessionMemory == null) {
                sendErrorMessage(sessionId, "会话记忆不存在");
                return;
            }

            String personaId = sessionMemory.getPersonaId();

            // 集成AI增强上下文（包含本地知识库和网络搜索）
            List<String> enhancedContexts;
            try {
                enhancedContexts = aiEnhancementService.getEnhancedContext(userText, 5);
                log.debug("获取到 {} 个增强上下文", enhancedContexts.size());
            } catch (Exception e) {
                log.warn("AI增强上下文获取失败，尝试本地知识库检索: {}", e.getMessage());
                // 降级到本地知识库检索
                try {
                    List<KnowledgeSnippet> knowledgeSnippets = knowledgeService.searchSnippets(userText, 3);
                    enhancedContexts = knowledgeSnippets.stream()
                            .map(snippet -> String.format("%s (%s)", snippet.getContent(), snippet.getCitationFormat()))
                            .collect(Collectors.toList());
                    log.debug("降级检索到 {} 个知识片段", enhancedContexts.size());
                } catch (Exception fallbackE) {
                    log.warn("本地知识库检索也失败，使用无上下文对话: {}", fallbackE.getMessage());
                    enhancedContexts = List.of(); // 使用空列表，不影响正常对话
                }
            }

            // 获取LLM流式响应
            Flux<String> responseStream = llmClient.streamChat(personaId, sessionId, userText, enhancedContexts);

            StringBuilder fullResponse = new StringBuilder();

            // 处理流式响应
            responseStream
                    .doOnNext(chunk -> {
                        // 发送流式文本块
                        WebSocketMessage partialMessage = WebSocketMessage.partialText(chunk);
                        messagingTemplate.convertAndSend("/topic/chat/" + sessionId, partialMessage);
                        fullResponse.append(chunk);
                    })
                    .doOnComplete(() -> {
                        try {
                            String completeResponse = fullResponse.toString();
                            log.info("LLM响应完成 - 会话: {}, 长度: {}", sessionId, completeResponse.length());

                            // 发送完整响应
                            WebSocketMessage finalMessage = WebSocketMessage.finalText(completeResponse);
                            messagingTemplate.convertAndSend("/topic/chat/" + sessionId, finalMessage);

                            // 更新会话记忆
                            sessionService.updateSessionMemory(sessionId, userText, completeResponse,
                                    SessionMemory.MessageType.TEXT, List.of(Skill.MEMORY));

                            // 异步生成TTS音频
                            generateTTSAsync(sessionId, completeResponse);

                        } catch (Exception e) {
                            log.error("处理LLM响应完成事件失败", e);
                            sendErrorMessage(sessionId, "处理响应失败");
                        }
                    })
                    .doOnError(error -> {
                        log.error("LLM流式响应出错", error);
                        sendErrorMessage(sessionId, "LLM响应失败: " + error.getMessage());
                    })
                    .subscribe(); // 启动流式处理

        } catch (Exception e) {
            log.error("处理文本消息失败", e);
            sendErrorMessage(sessionId, "处理失败: " + e.getMessage());
        }
    }

    /**
     * 异步生成TTS音频
     */
    private void generateTTSAsync(String sessionId, String text) {
        try {
            // 获取会话信息和角色
            SessionMemory sessionMemory = sessionService.getSessionMemory(sessionId);
            if (sessionMemory == null) {
                log.warn("会话记忆不存在，跳过TTS生成: {}", sessionId);
                return;
            }
            
            String personaId = sessionMemory.getPersonaId();
            Persona persona = personaService.getPersonaById(personaId);
            
            // 获取角色对应的声音
            String voiceName; // 默认声音
            if (persona != null && persona.getStyle() != null && persona.getStyle().getVoiceName() != null) {
                voiceName = persona.getStyle().getVoiceName();
            } else {
                voiceName = "tongtong";
            }

            log.info("为角色 {} 使用声音 {} 生成TTS", personaId, voiceName);
            
            // 使用流式TTS生成音频
            Flux<byte[]> audioStream = ttsClient.synthesizeStream(text, voiceName, "zh-CN");

            audioStream
                    .doOnNext(audioChunk -> {
                        // 将音频块编码为Base64并发送
                        String encodedAudio = Base64.getEncoder().encodeToString(audioChunk);
                        WebSocketMessage audioMessage = WebSocketMessage.audioChunk(encodedAudio, "mp3");
                        messagingTemplate.convertAndSend("/topic/chat/" + sessionId, audioMessage);
                    })
                    .doOnComplete(() -> {
                        log.info("TTS音频生成完成 - 会话: {}, 声音: {}", sessionId, voiceName);
                        
                        // 发送音频完成状态
                        WebSocketMessage statusMessage = WebSocketMessage.builder()
                                .type(WebSocketMessage.MessageType.STATUS)
                                .content("TTS_COMPLETE")
                                .timestamp(System.currentTimeMillis())
                                .build();
                        messagingTemplate.convertAndSend("/topic/chat/" + sessionId, statusMessage);
                    })
                    .doOnError(error -> {
                        log.error("TTS生成失败: {}", error.getMessage());
                        // 检查是否是余额不足错误
                        if (error.getMessage().contains("余额不足") || error.getMessage().contains("429")) {
                            // 发送友好的错误提示
                            WebSocketMessage statusMessage = WebSocketMessage.builder()
                                    .type(WebSocketMessage.MessageType.STATUS)
                                    .content("语音合成服务余额不足，文本回复已完成。")
                                    .timestamp(System.currentTimeMillis())
                                    .build();
                            messagingTemplate.convertAndSend("/topic/chat/" + sessionId, statusMessage);
                        } else {
                            sendErrorMessage(sessionId, "语音合成失败，但文本回复已完成。");
                        }
                    })
                    .subscribe(); // 启动异步处理

        } catch (Exception e) {
            log.error("启动TTS异步生成失败", e);
            // 不阻塞正常的文本对话流程
            WebSocketMessage statusMessage = WebSocketMessage.builder()
                    .type(WebSocketMessage.MessageType.STATUS)
                    .content("语音合成服务不可用，文本回复已完成。")
                    .timestamp(System.currentTimeMillis())
                    .build();
            messagingTemplate.convertAndSend("/topic/chat/" + sessionId, statusMessage);
        }
    }

    /**
     * 发送错误消息
     */
    private void sendErrorMessage(String sessionId, String errorMessage) {
        WebSocketMessage errorMsg = WebSocketMessage.error(errorMessage);
        messagingTemplate.convertAndSend("/topic/chat/" + sessionId, errorMsg);
    }
}